/*
 * Designed and developed by 2017 skydoves (Jaewoong Eum)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.skydoves.colorpickerview;

import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import android.widget.ImageView;

import androidx.annotation.ColorInt;
import androidx.annotation.ColorRes;
import androidx.annotation.FloatRange;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.Px;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.Lifecycle;
import androidx.lifecycle.LifecycleObserver;
import androidx.lifecycle.LifecycleOwner;
import androidx.lifecycle.OnLifecycleEvent;

import com.skydoves.colorpickerview.flag.FlagMode;
import com.skydoves.colorpickerview.flag.FlagView;
import com.skydoves.colorpickerview.listeners.ColorEnvelopeListener;
import com.skydoves.colorpickerview.listeners.ColorListener;
import com.skydoves.colorpickerview.listeners.ColorPickerViewListener;
import com.skydoves.colorpickerview.preference.ColorPickerPreferenceManager;
import com.skydoves.colorpickerview.sliders.AlphaSlideBar;
import com.skydoves.colorpickerview.sliders.BrightnessSlideBar;

/**
 * ColorPickerView 是一个强大的颜色选择组件，支持从各种图片资源中获取HSV颜色、ARGB值和十六进制颜色代码。
 * 
 * <p>该组件提供两种主要的调色板模式：
 * 1. 圆形HSV调色板 - 基于色相、饱和度和明度的传统圆形调色板
 * 2. 线性彩虹条调色板 - 水平渐变的彩虹条调色板，专注于色相选择
 * 
 * <p>当用户与组件交互时，{@link ColorPickerViewListener} 将根据设置的 {@link ActionMode} 规则被触发。
 * 
 * <p>可选组件包括：
 * - {@link FlagView} - 显示选定颜色信息的标记视图
 * - {@link AlphaSlideBar} - 调整颜色透明度的滑动条
 * - {@link BrightnessSlideBar} - 调整颜色亮度的滑动条
 */
@SuppressWarnings("unused")
public class ColorPickerView extends FrameLayout implements LifecycleObserver {

  /**
   * 当前选择的纯色（不包含透明度和亮度调整）
   * 存储从调色板中直接选择的原始颜色值
   */
  @ColorInt
  private int selectedPureColor;
  
  /**
   * 当前选择的最终颜色（可能包含透明度和亮度调整）
   * 这是应用了alpha和亮度滑块调整后的最终输出颜色
   */
  @ColorInt
  private int selectedColor;
  
  /**
   * 当前选择器在调色板上的位置坐标
   * 记录用户当前选择的精确像素点
   */
  private Point selectedPoint;
  
  /**
   * 调色板视图
   * 用于显示颜色选择区域（圆形HSV或线性彩虹条）
   */
  private ImageView palette;
  
  /**
   * 选择器视图
   * 用于在调色板上指示当前选择位置的指示器
   */
  private ImageView selector;
  
  /**
   * 标记视图
   * 用于显示选定颜色信息的可选组件
   */
  private FlagView flagView;
  
  /**
   * 调色板的可绘制对象
   * 存储调色板的视觉表示（HSV圆或线性彩虹条）
   */
  private Drawable paletteDrawable;
  
  /**
   * 选择器的可绘制对象
   * 存储选择指示器的视觉表示
   */
  private Drawable selectorDrawable;
  
  /**
   * 透明度滑动条
   * 用于调整选定颜色的透明度
   */
  private AlphaSlideBar alphaSlideBar;
  
  /**
   * 亮度滑动条
   * 用于调整选定颜色的亮度
   */
  private BrightnessSlideBar brightnessSlider;
  
  /**
   * 颜色监听器
   * 当颜色发生变化时接收回调通知
   */
  public ColorPickerViewListener colorListener;
  
  /**
   * 防抖延迟时间（毫秒）
   * 用于限制颜色变化事件的触发频率，避免频繁回调
   */
  private long debounceDuration = 0;
  
  /**
   * 用于实现防抖功能的Handler
   */
  private final Handler debounceHandler = new Handler();

  /**
   * 颜色监听器的触发动作模式
   * 默认值为ALWAYS，即每次用户交互都会触发
   */
  private ActionMode actionMode = ActionMode.ALWAYS;

  /**
   * 定义颜色监听器的触发动作模式枚举
   * 控制何时向监听器发送颜色变化通知
   */
  public enum ActionMode {
    /**
     * ALWAYS模式：每次用户触摸调色板时都触发监听器回调
     * 适用于需要实时响应颜色变化的场景
     */
    ALWAYS,
    /**
     * LAST模式：仅在用户释放触摸时触发最后一次监听器回调
     * 适用于需要减少回调次数、优化性能的场景
     */
    LAST
  }

  /**
   * 选择器的透明度
   * 取值范围为0.0到1.0，默认为1.0（完全不透明）
   */
  @FloatRange(from = 0.0, to = 1.0)
  private float selector_alpha = 1.0f;

  /**
   * 标记视图的透明度
   * 取值范围为0.0到1.0，默认为1.0（完全不透明）
   */
  @FloatRange(from = 0.0, to = 1.0)
  private float flag_alpha = 1.0f;

  /**
   * 标记视图是否可翻转
   * 设置为true时，标记会根据位置自动翻转以确保可见性
   */
  private boolean flag_isFlipAble = true;

  /**
   * 选择器的尺寸（像素）
   * 控制选择指示器的大小
   */
  @Px
  private int selectorSize = 0;

  /**
   * 视图可见性标志
   * 用于控制选择器和标记视图的显示/隐藏动画
   */
  private boolean VISIBLE_FLAG = false;

  /**
   * 首选项名称
   * 用于持久化和恢复选择器和滑动条状态
   */
  private String preferenceName;
  
  /**
   * 颜色选择器首选项管理器
   * 单例模式，负责保存和恢复颜色选择器的状态
   */
  private final ColorPickerPreferenceManager preferenceManager =
    ColorPickerPreferenceManager.getInstance(getContext());
  
  /**
   * 线性调色板标志位
   * true表示使用线性彩虹条调色板，false表示使用圆形HSV调色板
   */
  private boolean useLinearPalette = false;
  private float linearPaletteRadius = 0f; // 线性调色板圆角半径
  private boolean showFlagView = true; // 是否显示颜色指示器

  public ColorPickerView(Context context) {
    super(context);
  }

  public ColorPickerView(Context context, AttributeSet attrs) {
    super(context, attrs);
    getAttrs(attrs);
    onCreate();
  }

  public ColorPickerView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    getAttrs(attrs);
    onCreate();
  }

  @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  public ColorPickerView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
    super(context, attrs, defStyleAttr, defStyleRes);
    getAttrs(attrs);
    onCreate();
  }

  private void getAttrs(AttributeSet attrs) {
    TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.ColorPickerView);
    try {
      if (a.hasValue(R.styleable.ColorPickerView_palette)) {
        this.paletteDrawable = a.getDrawable(R.styleable.ColorPickerView_palette);
      }
      if (a.hasValue(R.styleable.ColorPickerView_selector)) {
        int resourceId = a.getResourceId(R.styleable.ColorPickerView_selector, -1);
        if (resourceId != -1) {
          this.selectorDrawable = AppCompatResources.getDrawable(getContext(), resourceId);
        }
      }
      if (a.hasValue(R.styleable.ColorPickerView_selector_alpha)) {
        this.selector_alpha =
          a.getFloat(R.styleable.ColorPickerView_selector_alpha, selector_alpha);
      }
      if (a.hasValue(R.styleable.ColorPickerView_selector_size)) {
        this.selectorSize =
          a.getDimensionPixelSize(R.styleable.ColorPickerView_selector_size, selectorSize);
      }
      if (a.hasValue(R.styleable.ColorPickerView_flag_alpha)) {
        this.flag_alpha = a.getFloat(R.styleable.ColorPickerView_flag_alpha, flag_alpha);
      }
      if (a.hasValue(R.styleable.ColorPickerView_flag_isFlipAble)) {
        this.flag_isFlipAble =
          a.getBoolean(R.styleable.ColorPickerView_flag_isFlipAble, flag_isFlipAble);
      }
      if (a.hasValue(R.styleable.ColorPickerView_actionMode)) {
        int actionMode = a.getInteger(R.styleable.ColorPickerView_actionMode, 0);
        if (actionMode == 0) {
          this.actionMode = ActionMode.ALWAYS;
        } else if (actionMode == 1) this.actionMode = ActionMode.LAST;
      }
      if (a.hasValue(R.styleable.ColorPickerView_debounceDuration)) {
        this.debounceDuration =
          a.getInteger(R.styleable.ColorPickerView_debounceDuration, (int) debounceDuration);
      }
      if (a.hasValue(R.styleable.ColorPickerView_preferenceName)) {
        this.preferenceName = a.getString(R.styleable.ColorPickerView_preferenceName);
      }
      if (a.hasValue(R.styleable.ColorPickerView_initialColor)) {
        setInitialColor(a.getColor(R.styleable.ColorPickerView_initialColor, Color.WHITE));
      }
      // 读取是否使用线性调色板的属性
      if (a.hasValue(R.styleable.ColorPickerView_useLinearPalette)) {
        this.useLinearPalette = a.getBoolean(R.styleable.ColorPickerView_useLinearPalette, useLinearPalette);
      }
      // 读取线性调色板圆角半径属性
      if (a.hasValue(R.styleable.ColorPickerView_linearPaletteRadius)) {
        this.linearPaletteRadius = a.getDimension(R.styleable.ColorPickerView_linearPaletteRadius, 0f);
      }
      // 读取是否显示颜色指示器属性
      if (a.hasValue(R.styleable.ColorPickerView_showFlagView)) {
        this.showFlagView = a.getBoolean(R.styleable.ColorPickerView_showFlagView, true);
      }
    } finally {
      a.recycle();
    }
  }

  private void onCreate() {
    setPadding(0, 0, 0, 0);
    palette = new ImageView(getContext());
    if (paletteDrawable != null) {
      palette.setImageDrawable(paletteDrawable);
    }

    FrameLayout.LayoutParams paletteParam =
      new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
    paletteParam.gravity = Gravity.CENTER;
    addView(palette, paletteParam);

    selector = new ImageView(getContext());
    if (selectorDrawable != null) {
      selector.setImageDrawable(selectorDrawable);
    } else {
      selector.setImageDrawable(ContextCompat.getDrawable(getContext(), R.drawable.colorpickerview_wheel));
    }
    FrameLayout.LayoutParams selectorParam =
      new LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
    if (selectorSize != 0) {
      selectorParam.width = SizeUtils.dp2Px(getContext(), selectorSize);
      selectorParam.height = SizeUtils.dp2Px(getContext(), selectorSize);
    }
    selectorParam.gravity = Gravity.CENTER;
    addView(selector, selectorParam);
    selector.setAlpha(selector_alpha);

    getViewTreeObserver()
      .addOnGlobalLayoutListener(
        new ViewTreeObserver.OnGlobalLayoutListener() {
          @Override
          public void onGlobalLayout() {
            getViewTreeObserver().removeOnGlobalLayoutListener(this);
            onFinishInflated();
          }
        });
  }

  @Override
  protected void onSizeChanged(int width, int height, int oldWidth, int oldHeight) {
    super.onSizeChanged(width, height, oldWidth, oldHeight);

    if (palette.getDrawable() == null) {
      Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
      if (useLinearPalette) {
          ColorLinearPalette colorLinearPalette = new ColorLinearPalette(getResources(), bitmap);
          // 应用圆角设置
          colorLinearPalette.setRadius(linearPaletteRadius);
          palette.setImageDrawable(colorLinearPalette);
      } else {
        palette.setImageDrawable(new ColorHsvPalette(getResources(), bitmap));
      }
    }
  }

  private void onFinishInflated() {
    if (getParent() != null && getParent() instanceof ViewGroup) {
      ((ViewGroup) getParent()).setClipChildren(false);
    }

    if (getPreferenceName() != null) {
      preferenceManager.restoreColorPickerData(this);
      final int persisted = preferenceManager.getColor(getPreferenceName(), -1);
      if (palette.getDrawable() instanceof ColorHsvPalette && persisted != -1) {
        post(
          () -> {
            try {
              selectByHsvColor(persisted);
            } catch (IllegalAccessException e) {
              e.printStackTrace();
            }
          });
      }
    } else {
      selectCenter();
    }
  }

  /**
   * initialize the {@link ColorPickerView} by {@link ColorPickerView.Builder}.
   *
   * @param builder {@link ColorPickerView.Builder}.
   */
  protected void onCreateByBuilder(Builder builder) {
    FrameLayout.LayoutParams params =
      new FrameLayout.LayoutParams(
        SizeUtils.dp2Px(getContext(), builder.width),
        SizeUtils.dp2Px(getContext(), builder.height));
    setLayoutParams(params);

    this.paletteDrawable = builder.paletteDrawable;
    this.selectorDrawable = builder.selectorDrawable;
    this.selector_alpha = builder.selector_alpha;
    this.flag_alpha = builder.flag_alpha;
    this.selectorSize = SizeUtils.dp2Px(getContext(), builder.selectorSize);
    this.debounceDuration = builder.debounceDuration;
    this.useLinearPalette = builder.useLinearPalette;
    onCreate();

    if (builder.colorPickerViewListener != null) setColorListener(builder.colorPickerViewListener);
    if (builder.alphaSlideBar != null) attachAlphaSlider(builder.alphaSlideBar);
    if (builder.brightnessSlider != null) attachBrightnessSlider(builder.brightnessSlider);
    if (builder.actionMode != null) this.actionMode = builder.actionMode;
    if (builder.flagView != null) setFlagView(builder.flagView);
    if (builder.preferenceName != null) setPreferenceName(builder.preferenceName);
    if (builder.initialColor != 0) setInitialColor(builder.initialColor);
    if (builder.lifecycleOwner != null) setLifecycleOwner(builder.lifecycleOwner);
  }

  @SuppressLint("ClickableViewAccessibility")
  @Override
  public boolean onTouchEvent(MotionEvent event) {
    if (!this.isEnabled()) {
      return false;
    }
    switch (event.getActionMasked()) {
      case MotionEvent.ACTION_DOWN:
      case MotionEvent.ACTION_MOVE:
      case MotionEvent.ACTION_UP:
        // 只有在showFlagView为true时才传递触摸事件给flagView
        if (showFlagView && getFlagView() != null) {
          getFlagView().receiveOnTouchEvent(event);
        }
        selector.setPressed(true);
        return onTouchReceived(event);
      default:
        selector.setPressed(false);
        return false;
    }
  }

  /**
   * 处理触摸事件并通知相关视图
   * 当用户点击或移动时，此方法会：
   * 1. 计算触摸位置对应的颜色点
   * 2. 获取该位置的颜色值
   * 3. 更新当前选择的颜色和位置
   * 4. 移动选择器到对应位置
   * 5. 根据设置的动作模式触发颜色变化通知
   * 
   * @param event 触摸事件对象
   * @return 总是返回true表示已处理事件
   */
  @MainThread
  private boolean onTouchReceived(final MotionEvent event) {
    Point snapPoint = PointMapper.getColorPoint(this, new Point((int) event.getX(), (int) event.getY()));
    int pixelColor = getColorFromBitmap(snapPoint.x, snapPoint.y);

    this.selectedPureColor = pixelColor;
    this.selectedColor = pixelColor;
    this.selectedPoint = PointMapper.getColorPoint(this, new Point(snapPoint.x, snapPoint.y));
    setCoordinate(snapPoint.x, snapPoint.y);

    if (actionMode == ActionMode.LAST) {
      notifyToFlagView(this.selectedPoint);
      if (event.getAction() == MotionEvent.ACTION_UP) {
        notifyColorChanged();
      }
    } else {
      notifyColorChanged();
    }
    return true;
  }

  public boolean isHuePalette() {
    return palette.getDrawable() != null && palette.getDrawable() instanceof ColorHsvPalette;
  }
  
  /**
   * 检查是否使用线性调色板
   * @return 如果使用线性调色板则返回true
   */
  public boolean isLinearPalette() {
    return palette.getDrawable() != null && palette.getDrawable() instanceof ColorLinearPalette;
  }

  /**
   * 通知颜色变化到各相关组件
   * 使用防抖机制避免频繁回调，确保在指定的延迟时间内只有最后一次颜色变化被通知
   * 通知的对象包括：
   * - 颜色监听器（ColorListener）
   * - 标记视图（FlagView）
   * - 透明度滑动条（AlphaSlideBar）
   * - 亮度滑动条（BrightnessSlideBar）
   */
  private void notifyColorChanged() {
    this.debounceHandler.removeCallbacksAndMessages(null);
    Runnable debounceRunnable = () -> {
      fireColorListener(getColor(), true);
      notifyToFlagView(selectedPoint);
    };
    this.debounceHandler.postDelayed(debounceRunnable, this.debounceDuration);
  }

  /**
   * 从指定坐标获取调色板上的像素颜色
   * 根据不同类型的调色板使用不同的颜色获取算法：
   * - 对于HSV圆形调色板，根据极坐标计算颜色
   * - 对于线性彩虹条调色板，主要根据x坐标比例确定色相
   * - 对于其他位图调色板，直接从对应的像素位置获取颜色值
   * 
   * @param x 触摸点的x坐标
   * @param y 触摸点的y坐标
   * @return 对应位置的颜色值，以ARGB整数形式返回
   */
  protected int getColorFromBitmap(float x, float y) {
    Matrix invertMatrix = new Matrix();
    palette.getImageMatrix().invert(invertMatrix);

    float[] mappedPoints = new float[]{x, y};
    invertMatrix.mapPoints(mappedPoints);

    if (palette.getDrawable() != null
      && palette.getDrawable() instanceof BitmapDrawable
      && mappedPoints[0] >= 0
      && mappedPoints[1] >= 0
      && mappedPoints[0] < palette.getDrawable().getIntrinsicWidth()
      && mappedPoints[1] < palette.getDrawable().getIntrinsicHeight()) {

      invalidate();

      if (palette.getDrawable() instanceof ColorHsvPalette) {
        x = x - getWidth() * 0.5f;
        y = y - getHeight() * 0.5f;
        double r = Math.sqrt(x * x + y * y);
        float radius = Math.min(getWidth(), getHeight()) * 0.5f;
        float[] hsv = {0, 0, 1};
        hsv[0] = (float) (Math.atan2(y, -x) / Math.PI * 180f) + 180;
        hsv[1] = Math.max(0f, Math.min(1f, (float) (r / radius)));
        return Color.HSVToColor(hsv);
      } else if (palette.getDrawable() instanceof ColorLinearPalette) {
        // 对于线性调色板，主要根据x坐标确定颜色（水平渐变）
        // 计算x坐标在整个宽度中的比例（0.0-1.0）
        float hue = Math.max(0f, Math.min(1f, mappedPoints[0] / palette.getDrawable().getIntrinsicWidth())) * 360f;
        float[] hsv = {hue, 1f, 1f}; // 最大饱和度和亮度
        return Color.HSVToColor(hsv);
      } else {
        Rect rect = palette.getDrawable().getBounds();
        float scaleX = mappedPoints[0] / rect.width();
        int x1 = (int) (scaleX * ((BitmapDrawable) palette.getDrawable()).getBitmap().getWidth());
        float scaleY = mappedPoints[1] / rect.height();
        int y1 = (int) (scaleY * ((BitmapDrawable) palette.getDrawable()).getBitmap().getHeight());
        return ((BitmapDrawable) palette.getDrawable()).getBitmap().getPixel(x1, y1);
      }
    }
    return 0;
  }

  /**
   * sets a {@link ColorPickerViewListener} on the {@link ColorPickerView}.
   *
   * @param colorListener {@link ColorListener} or {@link ColorEnvelopeListener}.
   */
  public void setColorListener(ColorPickerViewListener colorListener) {
    this.colorListener = colorListener;
  }

  /**
   * invokes {@link ColorListener} or {@link ColorEnvelopeListener} with a color value.
   *
   * @param color    color.
   * @param fromUser triggered by user or not.
   */
  public void fireColorListener(@ColorInt int color, final boolean fromUser) {
    this.selectedColor = color;
    if (getAlphaSlideBar() != null) {
      getAlphaSlideBar().notifyColor();
      this.selectedColor = getAlphaSlideBar().assembleColor();
    }
    if (getBrightnessSlider() != null) {
      getBrightnessSlider().notifyColor();
      this.selectedColor = getBrightnessSlider().assembleColor();
    }

    if (this.colorListener != null) {
      if (colorListener instanceof ColorListener) {
        ((ColorListener) colorListener).onColorSelected(selectedColor, fromUser);
      } else if (colorListener instanceof ColorEnvelopeListener) {
        ColorEnvelope envelope = new ColorEnvelope(selectedColor);
        ((ColorEnvelopeListener) colorListener).onColorSelected(envelope, fromUser);
      }
    }

    if (this.flagView != null) {
      this.flagView.onRefresh(getColorEnvelope());
      invalidate();
    }

    if (VISIBLE_FLAG) {
      VISIBLE_FLAG = false;
      if (this.selector != null) {
        this.selector.setAlpha(selector_alpha);
      }
      if (this.flagView != null) {
        this.flagView.setAlpha(flag_alpha);
      }
    }
  }

  /**
   * notify to sliders about a new trigger.
   */
  private void notifyToSlideBars() {
    if (alphaSlideBar != null) alphaSlideBar.notifyColor();
    if (brightnessSlider != null) {
      brightnessSlider.notifyColor();

      if (brightnessSlider.assembleColor() != Color.WHITE) {
        selectedColor = brightnessSlider.assembleColor();
      } else if (alphaSlideBar != null) selectedColor = alphaSlideBar.assembleColor();
    }
  }

  /**
   * 通知flagView更新其位置和显示的颜色
   * @param point 当前选中的坐标点
   */
  private void notifyToFlagView(Point point) {
    // 如果showFlagView为false，确保flagView不显示
    if (!showFlagView) {
      if (flagView != null) {
        flagView.gone();
      }
      return;
    }
    
    // 只有当showFlagView为true且flagView不为空时才更新
    if (flagView != null) {
      Point centerPoint = getCenterPoint(point.x, point.y);
      if (flagView.getFlagMode() == FlagMode.ALWAYS) flagView.visible();
      int posX = centerPoint.x - flagView.getWidth() / 2 + selector.getWidth() / 2;
      if (flagView.isFlipAble()) {
        if (centerPoint.y - flagView.getHeight() > 0) {
          flagView.setRotation(0);
          flagView.setX(posX);
          flagView.setY(centerPoint.y - flagView.getHeight());
          flagView.onFlipped(false);
        } else {
          flagView.setRotation(180);
          flagView.setX(posX);
          flagView.setY(centerPoint.y + flagView.getHeight() - selector.getHeight() * 0.5f);
          flagView.onFlipped(true);
        }
      } else {
        flagView.setRotation(0);
        flagView.setX(posX);
        flagView.setY(centerPoint.y - flagView.getHeight());
      }
      flagView.onRefresh(getColorEnvelope());
      if (posX < 0) flagView.setX(0);
      if (posX + flagView.getWidth() > getWidth()) {
        flagView.setX(getWidth() - flagView.getWidth());
      }
    }
  }

  /**
   * 获取当前选择的最终颜色值
   * 这是经过透明度和亮度调整后的最终颜色
   * 
   * @return 当前选择的颜色值，以ARGB整数形式返回
   */
  public @ColorInt int getColor() {
    return selectedColor;
  }

  /**
   * 获取当前选择颜色的透明度值
   * 将0-255范围内的alpha值转换为0.0-1.0的浮点数
   * 
   * @return 透明度值，范围为0.0（完全透明）到1.0（完全不透明）
   */
  public @FloatRange(from = 0.0, to = 1.0) float getAlpha() {
    return Color.alpha(getColor()) / 255f;
  }

  /**
   * gets the selected pure color without alpha and brightness.
   *
   * @return the selected pure color.
   */
  public @ColorInt int getPureColor() {
    return selectedPureColor;
  }

  /**
   * sets the pure color.
   *
   * @param color the pure color.
   */
  public void setPureColor(@ColorInt int color) {
    this.selectedPureColor = color;
  }

  /**
   * gets the {@link ColorEnvelope} of the selected color.
   *
   * @return {@link ColorEnvelope}.
   */
  public ColorEnvelope getColorEnvelope() {
    return new ColorEnvelope(getColor());
  }

  /**
   * gets a {@link FlagView}.
   *
   * @return {@link FlagView}.
   */
  public FlagView getFlagView() {
    return this.flagView;
  }

  /**
   * sets a {@link FlagView}.
   *
   * @param flagView {@link FlagView}.
   */
  public void setFlagView(@NonNull FlagView flagView) {
    flagView.gone();
    addView(flagView);
    this.flagView = flagView;
    flagView.setAlpha(flag_alpha);
    flagView.setFlipAble(flag_isFlipAble);
  }

  /**
   * gets a debounce duration.
   *
   * <p>only emit a color to the listener if a particular timespan has passed without it emitting
   * another value.
   *
   * @return debounceDuration.
   */
  public long getDebounceDuration() {
    return this.debounceDuration;
  }

  /**
   * 设置颜色变化通知的防抖延迟时间
   * 防抖机制确保在指定的时间间隔内，如果没有新的颜色变化事件，则只向监听器发送最后一次颜色值
   * 这样可以减少不必要的回调，提高性能，特别是在用户快速滑动选择器时
   * 
   * @param debounceDuration 防抖延迟时间（毫秒），值越大，通知频率越低
   */
  public void setDebounceDuration(long debounceDuration) {
    this.debounceDuration = debounceDuration;
  }

  /**
   * gets center coordinate of the selector.
   *
   * @param x coordinate x.
   * @param y coordinate y.
   * @return the center coordinate of the selector.
   */
  private Point getCenterPoint(int x, int y) {
    return new Point(x - (selector.getWidth() / 2), y - (selector.getMeasuredHeight() / 2));
  }

  /**
   * gets a selector.
   *
   * @return selector.
   */
  public ImageView getSelector() {
    return this.selector;
  }

  /**
   * gets a selector's selected coordinate x.
   *
   * @return a selected coordinate x.
   */
  public float getSelectorX() {
    return selector.getX() - (selector.getWidth() * 0.5f);
  }

  /**
   * gets a selector's selected coordinate y.
   *
   * @return a selected coordinate y.
   */
  public float getSelectorY() {
    return selector.getY() - (selector.getMeasuredHeight() * 0.5f);
  }

  /**
   * gets a selector's selected coordinate.
   *
   * @return a selected coordinate {@link Point}.
   */
  public Point getSelectedPoint() {
    return selectedPoint;
  }

  /**
   * 手动设置选择器的位置并通知相关组件
   * 此方法会：
   * 1. 将输入坐标映射到有效调色板区域
   * 2. 获取该位置的颜色值
   * 3. 更新内部颜色状态
   * 4. 移动选择器到指定位置
   * 5. 触发颜色监听器回调
   * 6. 通知标记视图更新显示
   * 
   * @param x 选择器的x坐标
   * @param y 选择器的y坐标
   */
  public void setSelectorPoint(int x, int y) {
    Point mappedPoint = PointMapper.getColorPoint(this, new Point(x, y));
    int color = getColorFromBitmap(mappedPoint.x, mappedPoint.y);
    selectedPureColor = color;
    selectedColor = color;
    selectedPoint = new Point(mappedPoint.x, mappedPoint.y);
    setCoordinate(mappedPoint.x, mappedPoint.y);
    fireColorListener(getColor(), false);
    notifyToFlagView(selectedPoint);
  }

  /**
   * moves selector's selected point with notifies about changes manually.
   *
   * @param x coordinate x of the selector.
   * @param y coordinate y of the selector.
   */
  public void moveSelectorPoint(int x, int y, @ColorInt int color) {
    selectedPureColor = color;
    selectedColor = color;
    selectedPoint = new Point(x, y);
    setCoordinate(x, y);
    fireColorListener(getColor(), false);
    notifyToFlagView(selectedPoint);
  }

  /**
   * changes selector's selected point without notifies.
   *
   * @param x coordinate x of the selector.
   * @param y coordinate y of the selector.
   */
  public void setCoordinate(int x, int y) {
    // 计算滑块中心点相对于控件的位置
    float halfWidth = selector.getWidth() * 0.5f;
    float halfHeight = selector.getMeasuredHeight() * 0.5f;
    
    // 计算可用区域（考虑滑块大小）
    float availableWidth = getWidth() - selector.getWidth();
    float availableHeight = getHeight() - selector.getMeasuredHeight();
    
    // 确保滑块完全在控件内
    float selectorX = x - halfWidth;
    float selectorY = y - halfHeight;
    
    // 应用边界检查
    selectorX = Math.max(0, Math.min(selectorX, availableWidth));
    selectorY = Math.max(0, Math.min(selectorY, availableHeight));
    
    // 设置滑块位置
    selector.setX(selectorX);
    selector.setY(selectorY);
  }

  /**
   * Sets the initial color when the {@link ColorPickerView} is first created.
   * This initial color is set only once when the {@link ColorPickerView} is first created.
   * The color's alpha will be ignored.
   * 
   * @param initialColor The initial color value to be shown on the {@link ColorPickerView}.
   */
  public void setInitialColor(@ColorInt final int color) {
    System.out.println("ColorPickerView: setInitialColor called with color: #" + Integer.toHexString(color));
    
    // 移除偏好设置的检查，确保每次都能设置初始颜色
    post(
      () -> {
        try {
          boolean isLinearPalette = palette != null && palette.getDrawable() instanceof ColorLinearPalette;
          System.out.println("ColorPickerView: Inside UI thread post - Palette type: " + (isLinearPalette ? "Linear" : "Circular"));
          
          // 强制使用setColorInternal方法，因为我们已经修改了它来支持彩虹条模式
          System.out.println("ColorPickerView: Force calling setColorInternal for testing");
          setColorInternal(color);
          
          // 额外的UI更新，确保视图刷新
          postInvalidate();
          System.out.println("ColorPickerView: Post invalidation requested");
        } catch (Exception e) {
          // 打印详细错误信息以便调试
          System.out.println("ColorPickerView: Exception in setInitialColor post block: " + e.getMessage());
          e.printStackTrace();
        }
      });
  }
  
  /**
   * 内部方法：直接设置颜色，用于彩虹条模式的初始颜色设置
   */
  private void setColorInternal(@ColorInt int color) {
    System.out.println("ColorPickerView: setColorInternal called with color: #" + Integer.toHexString(color));
    
    float[] hsv = new float[3];
    Color.colorToHSV(color, hsv);
    System.out.println("ColorPickerView: HSV values: [" + hsv[0] + ", " + hsv[1] + ", " + hsv[2] + "]");
    
    // 确保视图已经测量完成
    int width = getWidth();
    int height = getHeight();
    System.out.println("ColorPickerView: View dimensions - width: " + width + ", height: " + height);
    
    if (width <= 0 || height <= 0) {
      System.out.println("ColorPickerView: View not measured yet, skipping position calculation");
      // 即使视图未测量，也设置颜色值
      selectedPureColor = color;
      selectedColor = color;
      return;
    }
    
    // 对于彩虹条模式，直接根据色相值设置位置
    float hueRatio = hsv[0] / 360f;
    hueRatio = Math.max(0f, Math.min(1f, hueRatio));
    System.out.println("ColorPickerView: Hue ratio calculated: " + hueRatio);
    
    int pointX = Math.round(hueRatio * width);
    int pointY = height / 2;
    System.out.println("ColorPickerView: Calculated position - x: " + pointX + ", y: " + pointY);
    
    // 直接设置颜色和位置
    selectedPureColor = color;
    selectedColor = color;
    selectedPoint = new Point(pointX, pointY);
    System.out.println("ColorPickerView: Color values updated");
    
    // 设置坐标并刷新UI
    setCoordinate(pointX, pointY);
    System.out.println("ColorPickerView: Coordinates set");
    invalidate();
    System.out.println("ColorPickerView: View invalidated");
    
    // 触发监听器
    fireColorListener(color, false);
    System.out.println("ColorPickerView: Color listener fired");
    notifyToFlagView(selectedPoint);
    System.out.println("ColorPickerView: Flag view notified");
    
    // 更新亮度和透明度滑块
    if (getBrightnessSlider() != null) {
      getBrightnessSlider().setSelectorByHalfSelectorPosition(hsv[2]);
      System.out.println("ColorPickerView: Brightness slider updated");
    }
    if (getAlphaSlideBar() != null) {
      getAlphaSlideBar().setSelectorByHalfSelectorPosition(getAlpha());
      System.out.println("ColorPickerView: Alpha slider updated");
    }
  }

  /**
   * select a point by a specific color resource. this method will not work if the default palette
   * drawable is not {@link ColorHsvPalette}.
   *
   * @param colorRes a starting color resource.
   */
  public void setInitialColorRes(@ColorRes final int colorRes) {
    setInitialColor(ContextCompat.getColor(getContext(), colorRes));
  }

  /**
   * changes selector's selected point by a specific color.
   *
   * <p>It will throw an exception if the default palette drawable is not {@link ColorHsvPalette}.
   *
   * @param color color.
   */
  public void selectByHsvColor(@ColorInt int color) throws IllegalAccessException {
    float[] hsv = new float[3];
    Color.colorToHSV(color, hsv);
    
    Point mappedPoint;
    
    if (palette.getDrawable() instanceof ColorHsvPalette) {
      // 圆形HSV调色板的处理逻辑
      float centerX = getWidth() * 0.5f;
      float centerY = getHeight() * 0.5f;
      float radius = hsv[1] * Math.min(centerX, centerY);
      int pointX = (int) (radius * Math.cos(Math.toRadians(hsv[0])) + centerX);
      int pointY = (int) (-radius * Math.sin(Math.toRadians(hsv[0])) + centerY);

      mappedPoint = PointMapper.getColorPoint(this, new Point(pointX, pointY));
    } else if (palette.getDrawable() instanceof ColorLinearPalette) {
      // 线性彩虹条调色板的精确处理逻辑
      // 彩虹条只包含色相信息，饱和度和亮度会被忽略
      // 色相值直接映射到水平位置 (0-360° → 0-宽度)
      float hueRatio = hsv[0] / 360f;
      // 确保在有效范围内
      hueRatio = Math.max(0f, Math.min(1f, hueRatio));
      
      // 计算精确的x坐标
      int pointX = Math.round(hueRatio * getWidth());
      // y坐标取中间位置
      int pointY = getHeight() / 2;
      
      // 创建点并进行映射
      Point rawPoint = new Point(pointX, pointY);
      mappedPoint = PointMapper.getColorPoint(this, rawPoint);
      
      // 直接设置选择点和颜色，绕过映射可能带来的问题
      selectedPoint = new Point(mappedPoint.x, mappedPoint.y);
      selectedPureColor = color;
      selectedColor = color;
      
      // 直接设置坐标，不依赖映射后的结果
      setCoordinate(pointX, pointY);
      
      // 触发颜色变化监听器
      fireColorListener(color, false);
      notifyToFlagView(selectedPoint);
      
      // 更新亮度滑块
      if (getBrightnessSlider() != null) {
        getBrightnessSlider().setSelectorByHalfSelectorPosition(hsv[2]);
      }
      
      // 更新透明度滑块
      if (getAlphaSlideBar() != null) {
        getAlphaSlideBar().setSelectorByHalfSelectorPosition(getAlpha());
      }
      
      // 直接返回，避免执行下面的公共逻辑
      return;
    } else {
      throw new IllegalAccessException(
        "selectByHsvColor(@ColorInt int color) can be called only "
          + "when the palette is an instance of ColorHsvPalette or ColorLinearPalette.");
    }
    
    // 圆形调色板的公共处理逻辑
    selectedPureColor = color;
    selectedColor = color;
    selectedPoint = new Point(mappedPoint.x, mappedPoint.y);
    if (getAlphaSlideBar() != null) {
      getAlphaSlideBar().setSelectorByHalfSelectorPosition(getAlpha());
    }
    if (getBrightnessSlider() != null) {
      getBrightnessSlider().setSelectorByHalfSelectorPosition(hsv[2]);
    }
    setCoordinate(mappedPoint.x, mappedPoint.y);
    fireColorListener(getColor(), false);
    notifyToFlagView(selectedPoint);
  }

  /**
   * changes selector's selected point by a specific color resource.
   *
   * <p>It may not work properly if change the default palette drawable.
   *
   * @param resource a color resource.
   */
  public void selectByHsvColorRes(@ColorRes int resource) throws IllegalAccessException {
    selectByHsvColor(ContextCompat.getColor(getContext(), resource));
  }

  /**
   * The default palette drawable is {@link ColorHsvPalette} if not be set the palette drawable
   * manually. This method can be used for changing as {@link ColorHsvPalette} from another palette
   * drawable.
   */
  public void setHsvPaletteDrawable() {
    Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
    setPaletteDrawable(new ColorHsvPalette(getResources(), bitmap));
  }

  /**
   * 设置线性渐变调色板（彩虹条）
   * 创建一个水平渐变的彩虹色条，提供线性的颜色选择体验
   * 与默认的圆形HSV调色板相比，线性调色板更适合需要直观选择不同色相的场景
   */
  public void setLinearPaletteDrawable() {
    Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_8888);
    ColorLinearPalette colorLinearPalette = new ColorLinearPalette(getResources(), bitmap);
      // 应用圆角设置
      colorLinearPalette.setRadius(linearPaletteRadius);
      setPaletteDrawable(colorLinearPalette);
  }
  
  /**
   * 设置线性调色板(彩虹条)的圆角半径
   * @param radius 圆角半径值（像素）
   */
  public void setLinearPaletteRadius(float radius) {
    this.linearPaletteRadius = radius;
    // 如果当前使用的是线性调色板，应用圆角设置
    if (palette.getDrawable() instanceof ColorLinearPalette) {
      ((ColorLinearPalette)palette.getDrawable()).setRadius(radius);
      invalidate();
    }
  }
  
  /**
   * 获取线性调色板的圆角半径
   * @return 当前圆角半径值
   */
  public float getLinearPaletteRadius() {
    return linearPaletteRadius;
  }
  
  /**
   * 设置是否显示颜色指示器(flagView)
   * @param showFlagView 如果为true显示指示器，为false则隐藏
   */
  public void setShowFlagView(boolean showFlagView) {
    this.showFlagView = showFlagView;
    // 如果设置为不显示，立即隐藏当前的flagView
    if (!showFlagView && flagView != null && flagView.getVisibility() == VISIBLE) {
      flagView.gone();
    }
  }
  
  /**
   * 获取是否显示颜色指示器的状态
   * @return 当前是否显示指示器
   */
  public boolean isShowFlagView() {
    return showFlagView;
  }

  /**
   * changes palette drawable manually.
   *
   * @param drawable palette drawable.
   */
  public void setPaletteDrawable(Drawable drawable) {
    removeView(palette);
    palette = new ImageView(getContext());
    paletteDrawable = drawable;
    palette.setImageDrawable(paletteDrawable);
    addView(palette);

    removeView(selector);
    addView(selector);

    selectedPureColor = Color.WHITE;
    notifyToSlideBars();

    if (flagView != null) {
      removeView(flagView);
      addView(flagView);
    }

    if (!VISIBLE_FLAG) {
      VISIBLE_FLAG = true;
      if (selector != null) {
        selector_alpha = selector.getAlpha();
        selector.setAlpha(0.0f);
      }
      if (flagView != null) {
        flag_alpha = flagView.getAlpha();
        flagView.setAlpha(0.0f);
      }
    }
  }

  /**
   * changes selector drawable manually.
   *
   * @param drawable selector drawable.
   */
  public void setSelectorDrawable(Drawable drawable) {
    selector.setImageDrawable(drawable);
  }

  /**
   * selects the center of the palette manually.
   */
  public void selectCenter() {
    setSelectorPoint(getWidth() / 2, getMeasuredHeight() / 2);
  }

  /**
   * sets enabling or not the ColorPickerView and slide bars.
   *
   * @param enabled true/false flag for making enable or not.
   */
  @Override
  public void setEnabled(boolean enabled) {
    super.setEnabled(enabled);

    selector.setVisibility(enabled ? VISIBLE : INVISIBLE);

    if (getAlphaSlideBar() != null) {
      getAlphaSlideBar().setEnabled(enabled);
    }

    if (getBrightnessSlider() != null) {
      getBrightnessSlider().setEnabled(enabled);
    }

    if (enabled) {
      palette.clearColorFilter();
    } else {
      int color = Color.argb(70, 255, 255, 255);
      palette.setColorFilter(color);
    }
  }

  /**
   * gets an {@link ActionMode}.
   *
   * @return {@link ActionMode}.
   */
  public ActionMode getActionMode() {
    return this.actionMode;
  }

  /**
   * sets an {@link ActionMode}.
   *
   * @param actionMode {@link ActionMode}.
   */
  public void setActionMode(ActionMode actionMode) {
    this.actionMode = actionMode;
  }

  /**
   * gets an {@link AlphaSlideBar}.
   *
   * @return {@link AlphaSlideBar}.
   */
  public @Nullable AlphaSlideBar getAlphaSlideBar() {
    return alphaSlideBar;
  }

  /**
   * linking an {@link AlphaSlideBar} on the {@link ColorPickerView}.
   *
   * @param alphaSlideBar {@link AlphaSlideBar}.
   */
  public void attachAlphaSlider(@NonNull AlphaSlideBar alphaSlideBar) {
    this.alphaSlideBar = alphaSlideBar;
    alphaSlideBar.attachColorPickerView(this);
    alphaSlideBar.notifyColor();

    if (getPreferenceName() != null) {
      alphaSlideBar.setPreferenceName(getPreferenceName());
    }
  }

  /**
   * gets an {@link BrightnessSlideBar}.
   *
   * @return {@link BrightnessSlideBar}.
   */
  public @Nullable BrightnessSlideBar getBrightnessSlider() {
    return brightnessSlider;
  }

  /**
   * linking an {@link BrightnessSlideBar} on the {@link ColorPickerView}.
   *
   * @param brightnessSlider {@link BrightnessSlideBar}.
   */
  public void attachBrightnessSlider(@NonNull BrightnessSlideBar brightnessSlider) {
    this.brightnessSlider = brightnessSlider;
    brightnessSlider.attachColorPickerView(this);
    brightnessSlider.notifyColor();

    if (getPreferenceName() != null) {
      brightnessSlider.setPreferenceName(getPreferenceName());
    }
  }

  /**
   * gets the preference name.
   *
   * @return preference name.
   */
  public @Nullable String getPreferenceName() {
    return preferenceName;
  }

  /**
   * sets the preference name.
   *
   * @param preferenceName preference name.
   */
  public void setPreferenceName(@Nullable String preferenceName) {
    this.preferenceName = preferenceName;
    if (this.alphaSlideBar != null) {
      this.alphaSlideBar.setPreferenceName(preferenceName);
    }
    if (this.brightnessSlider != null) {
      this.brightnessSlider.setPreferenceName(preferenceName);
    }
  }

  /**
   * sets the {@link LifecycleOwner}.
   *
   * @param lifecycleOwner {@link LifecycleOwner}.
   */
  public void setLifecycleOwner(LifecycleOwner lifecycleOwner) {
    lifecycleOwner.getLifecycle().addObserver(this);
  }

  /**
   * removes this color picker observer from the the {@link LifecycleOwner}.
   *
   * @param lifecycleOwner {@link LifecycleOwner}.
   */
  public void removeLifecycleOwner(LifecycleOwner lifecycleOwner) {
    lifecycleOwner.getLifecycle().removeObserver(this);
  }

  /**
   * This method invoked by the {@link LifecycleOwner}'s life cycle.
   *
   * <p>OnDestroy would be called on the {@link LifecycleOwner}, all of the color picker data will
   * be saved automatically.
   */
  @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
  public void onDestroy() {
    preferenceManager.saveColorPickerData(this);
  }

  /**
   * Builder class for create {@link ColorPickerView}.
   */
  public static class Builder {
    private final Context context;
    private ColorPickerViewListener colorPickerViewListener;
    private int debounceDuration = 0;
    private FlagView flagView;
    private Drawable paletteDrawable;
    private Drawable selectorDrawable;
    private AlphaSlideBar alphaSlideBar;
    private BrightnessSlideBar brightnessSlider;
    private ActionMode actionMode = ActionMode.ALWAYS;
    @ColorInt
    private int initialColor = 0;

    @FloatRange(from = 0.0, to = 1.0)
    private float selector_alpha = 1.0f;

    @FloatRange(from = 0.0, to = 1.0)
    private float flag_alpha = 1.0f;

    private boolean flag_isFlipAble = false;
    private boolean useLinearPalette = false; // 标志位，用于表示是否使用线性调色板

    @Dp
    private int selectorSize = 0;
    @Dp
    private int width = LayoutParams.MATCH_PARENT;
    @Dp
    private int height = LayoutParams.MATCH_PARENT;
    private String preferenceName;
    private LifecycleOwner lifecycleOwner;

    public Builder(Context context) {
      this.context = context;
    }

    public Builder setColorListener(ColorPickerViewListener colorPickerViewListener) {
      this.colorPickerViewListener = colorPickerViewListener;
      return this;
    }

    public Builder setDebounceDuration(int debounceDuration) {
      this.debounceDuration = debounceDuration;
      return this;
    }

    public Builder setPaletteDrawable(@NonNull Drawable palette) {
      this.paletteDrawable = palette;
      return this;
    }
    
    /**
     * Sets a linear gradient palette with rainbow colors for a horizontal color strip effect.
     */
    public Builder useLinearPalette() {
      // 标记为使用线性调色板
      this.useLinearPalette = true;
      return this;
    }

    public Builder setSelectorDrawable(@NonNull Drawable selector) {
      this.selectorDrawable = selector;
      return this;
    }

    public Builder setFlagView(@NonNull FlagView flagView) {
      this.flagView = flagView;
      return this;
    }

    public Builder setAlphaSlideBar(AlphaSlideBar alphaSlideBar) {
      this.alphaSlideBar = alphaSlideBar;
      return this;
    }

    public Builder setBrightnessSlideBar(BrightnessSlideBar brightnessSlideBar) {
      this.brightnessSlider = brightnessSlideBar;
      return this;
    }

    public Builder setActionMode(ActionMode actionMode) {
      this.actionMode = actionMode;
      return this;
    }

    public Builder setSelectorAlpha(@FloatRange(from = 0.0, to = 1.0) float alpha) {
      this.selector_alpha = alpha;
      return this;
    }

    public Builder setFlagAlpha(@FloatRange(from = 0.0, to = 1.0) float alpha) {
      this.flag_alpha = alpha;
      return this;
    }

    public Builder setFlagIsFlipAble(boolean isFlipAble) {
      this.flag_isFlipAble = isFlipAble;
      return this;
    }

    public Builder setSelectorSize(@Dp int size) {
      this.selectorSize = size;
      return this;
    }

    public Builder setWidth(@Dp int width) {
      this.width = width;
      return this;
    }

    public Builder setHeight(@Dp int height) {
      this.height = height;
      return this;
    }

    public Builder setInitialColor(@ColorInt int initialColor) {
      this.initialColor = initialColor;
      return this;
    }

    public Builder setInitialColorRes(@ColorRes int initialColorRes) {
      this.initialColor = ContextCompat.getColor(context, initialColorRes);
      return this;
    }

    public Builder setPreferenceName(@Nullable String preferenceName) {
      this.preferenceName = preferenceName;
      return this;
    }

    public Builder setLifecycleOwner(LifecycleOwner lifecycleOwner) {
      this.lifecycleOwner = lifecycleOwner;
      return this;
    }

    public ColorPickerView build() {
      ColorPickerView colorPickerView = new ColorPickerView(context);
      colorPickerView.onCreateByBuilder(this);
      return colorPickerView;
    }
  }
}
